# 索引：支持索引的类型（列表、元组、字符串）
#       不支持索引的类型（集合、字典、整数）
list1 = [1,2,3,4,5,6] # 列表
#        0 1 2 3 4 5
#        -6  -5  -4  -3  -2 -1
tuple1 = (11,223,44,55,66)  # 元组
str1 = "1234567" # 字符串
# 不支持索引取值的数据类型：
set1 = {1,2,33,44,55} # 集合
# print(set1[0]) # 集合不支持索引取值的

dict1 = {"姓名":"张三","年龄":99}
# print(dict1[0]) # 字典不支持索引取值

# 单纯的重复，不是迭代
"""
i = 0  #  循环变量
while True: # 死循环
    print(i) #  每次都打印i的值
"""

# 迭代是一重复的过程，每次的结果都是基于上次的结果而来
"""
l = ['a','b','c'] # 定义l列表，里面有三个对象
i = 0 # 循环变量
while i < len(l): # 开始循环，i小于l列表的长度开始循环
    print(i)
    # 每次打印i的值
    # 第一次循环：i是0
    # 第二次循环：i是1
    # 第三次循环：i是2
    print(l[i])
    # 打印l列表的每次i索引位置的值
    # 第一次循环：l[i]  l[0]  == a
    # 第二次循环：l[i]  l[1]  == b
    # 第三次循环：l[i]  l[2]  == c
    i +=1
    # 每次循环变量+1；如果循环变量省略掉，会是死循环
"""

# 哪些数据类型需要这样迭代取值?
"""
l = ['a','b','c']
a = "abc"
t = ('a',"b",'c')
dic = {"name":"danna",'age':18}
i = 0
keys = list(dic.keys()) # 字典的内置方法，获取所有的键值
# print(list(keys)) # ['name','age']
values = dic.values() # 字典的内置方法，获取所有的value值
# print(list(values)) # ['danna',18]
items = dic.items() # 键值对，用元组存储返回的
# print(list(items)) # [('name', 'danna'), ('age', 18)]
while i<len(keys):
    print(keys[i])
    # 第一次循环：keys[0] == name
    # 第二次循环：keys[1] == age
    i+=1
"""

# 可迭代对象
a = 1
# a.__iter__()  # 说明整数没有迭代的方法
b = 1.1
# b.__iter__() # 浮点型没有可迭代的方法
c = 'hello'
# c.__iter__() # 字符串有可迭代的方法，它是可迭代的对象
d = ['a','b','c']
# d.__iter__() # 列表有可迭代的方法，他是可迭代的对象
g = (11,22,33)
# g.__iter__() # 元组是可迭代的对象
s = {1,22,33,44}
# s.__iter__() # 集合是可迭代的对象
e = {"name":"asd","age":99}
# e.__iter__() # 字典是可迭代的对象
"""
通过__iter__()方法检测到的；有这个方法的就是可迭代对象
                          没有这个方法的就是不可迭代对象
什么是迭代呢？
每一次的取值都是基于上一次的结果而来

【可迭代的对象】
列表、字符串、元组、集合、字典

【不可迭代的对象】
整数、浮点型
"""

# 字典迭代器
"""
dic = {"x":1,"y":2,'z':3}
# 把可迭代的对象变成迭代器
iter_dic = dic.__iter__() # 通过iter的方法创建了iter_dic迭代器对象
# 直接打印迭代器：会是迭代器的地址值
# print(iter_dic) # <dict_keyiterator object at 0x0000015EDFB03DB0>
# 怎么使用迭代器呢？
print(iter_dic.__next__())  # 取出迭代的下一次的值：x
print(iter_dic.__next__())  # 取出迭代的下一次的值：y
print(iter_dic.__next__())  # 取出迭代的下一次的值：z
# print(iter_dic.__next__())  # 取出迭代的下一次的值：报错了 StopIteration
"""

# 元组迭代器
"""
tuple2 = (11,22,33)
tuple_iter= tuple2.__iter__() # 通过tuple2创建了迭代器对象
# 取出元组迭代器下一次的值
print(next(tuple_iter)) # next 和__next__()是一样的；这里拿出来的值是：11
print(next(tuple_iter)) # next 和__next__()是一样的；这里拿出来的值是：22
print(next(tuple_iter)) # next 和__next__()是一样的；这里拿出来的值是：33
# print(next(tuple_iter)) # next 和__next__()是一样的；这里拿出来的值是：报错
"""

# 迭代器有一个误区
"""
str2 = "11223344556677"
print(str2.__iter__().__next__()) # 1
print(str2.__iter__().__next__()) # 1
print(str2.__iter__().__next__()) # 1
print(str2.__iter__().__next__()) # 1
print(str2.__iter__().__next__()) # 1
"""
"""
上面的代码块相当于每一次都是创建了一个新的迭代器对象
str2.__iter__().__next__() 永远拿到的都是一个迭代器的值
"""

# 迭代器为什么和for循环使用
dic3 = { 'x':1,'y' :2,'z':3}
dict3_iter = dic3.__iter__() # 创建了字典迭代器对象
# print(next(dict3_iter)) # x
# print(next(dict3_iter)) # y
# print(next(dict3_iter)) # z
# print(next(dict3_iter)) # 报错
# 为了解决以上错误 可以用异常捕获进行
"""
try：
   尝试执行
except：
   报错执行这里
else:
   只有代码不报错，才会执行这里
finally：
   不论成功与否，都会执行到这里
"""
"""
try:
    print(abc) # abc对象没有定义，执行会报错
except Exception as ec:
    print(f"代码出现异常了，请你检查！{ec}")
else:
    print("代码成功执行！")
finally:
    print("代码执行完毕！")
"""
"""
try:
    print(2+2)
except Exception as ec:
    print(f"代码异常！{ec}")
else:
    print("代码成功执行！")
finally:
    print("代码执行完毕！")
    """
"""
while True:
    try:
        print(next(dict3_iter))
        # x
        # y
        # z
    except StopIteration:
        break
        """
# 有没有可以自己变成迭代器，并且每次取出下一次循环的值
# 可以用：for循环
"""
dic4 = { 'x':1,'y' :2,'z':3}
for i in dic4:
    print(i)
    # 第一次循环：x
    # 第二次循环：y
    # 第三次循环：z
    """
"""
for循环会把可迭代的对象变成迭代器
当所有的对象值取出来以后，他不会报错，因为底层用了try、except处理
"""
# for i in range(10): # 循环10次
#     # 0 1 2 3 4 5 6 7 8 9
#     print(i)
"""
obj_iter = range(1,10) # 创建对象
print(obj_iter) # range(1, 10)
obj = obj_iter.__iter__() # 创建迭代器对象
print(next(obj)) # 1
print(next(obj)) # 2
print(next(obj)) # 3
"""

# 问题：用循环遍历obj的迭代器对象，会从几开始？
"""
print("============从刚才的3继续走for循环=============")
for i in obj:
    print(i)
print('再次')
for j in obj:
    print(j) # 这次是取空了，不会有任何信息打印
print("根据对象继续遍历")
for i in obj_iter:
    print(i)
    """

# 生成器
def gg():
    a = 1 # 局部变量
    while True: # 死循环
        yield a # 生成器关键字，可以把这里当成return
        a += 1 # 每次的a+1重新赋值

a1 = gg() # 通过gg函数赋值给a1对象
# print(a1) # 生成器的地址值
print(next(a1)) # 1
print(next(a1)) # 2
"""
生成器也是迭代器的一种，但是它只能迭代一次
"""






























